package com.xunmall.base.util;

import org.springframework.util.CollectionUtils;

import java.text.ParseException;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;

/**
 * @Author: WangYanjing
 * @Date: 2018/12/27 10:53
 * @Description: 日期格式化（或解析）工具，不参与其它模块的依赖。
 */
public class DateUtils {

    /**
     * 毫秒转化
     */
    public static final int D_MS_DAY = 3600 * 24 * 1000;
    public static final int D_MS_HOUR = 3600 * 1000;
    public static final int D_MS_MINUTE = 60 * 1000;

    public static final String[] WEEKDAY_NAME = new String[]{"星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"};

    /**
     * 秒数转化
     */
    public static final int D_S_DAY = 3600 * 24;
    public static final int D_S_HOUR = 3600;
    public static final int D_S_MINUTE = 60;

    public static final String DATE_FORMAT_YYYY = "yyyy";
    public static final String DATE_FORMAT_YYYYMM = "yyyyMM";
    public static final String DATE_FORMAT_YYYYMMDD = "yyyyMMdd";
    public static final String DATE_FORMAT_YYYY_MM = "yyyy-MM";
    public static final String DATE_FORMAT_YYYY_MM_DD = "yyyy-MM-dd";
    public static final String DATE_FORMAT_YYYY_MM_DD2 = "yyyy/MM/dd";
    public static final String DATE_FORMAT_YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_YYYY_MM_DD_HH_MM2 = "yyyy-MM-dd HH:mm";
    public static final String DATE_FORMAT_HH_MM2 = "HH:mm";
    public static final String DATE_FORMAT_YYYYMMDDHHMM = "yyyyMMddHHmm";
    // TASK#226 BY ZHANGLL START
    public static final String DATE_FORMAT_YYYY_MM_DD_HH_MM = "yyyy/MM/dd HH:mm";
    public static final String DATE_FORMAT_M_DD_H_MM = "M月dd日 H点mm分";

    // TASK#226 BY ZHANGLL ENDE
    public static final String DATE_FORMAT_HH_MM = "HH:mm";
    public static final DateTimeFormatter DF_HH_MM = DateTimeFormatter.ofPattern(DATE_FORMAT_HH_MM);
    public static final String DATE_FORMAT_H_MM = "H点mm分";
    public static final String DATE_FORMAT_MM_DD = "MM月dd日";
    public static final String DATE_FORMAT_M_DD = "M月dd日";
    public static final String DATE_FORMAT_MM_DD2 = "MM-dd";
    public static final String DATE_FORMAT_YYYY_MM2 = "yyyy年MM月";

    // 获取两个时间的差距的天数
    public static int diffDays(Date date1, Date date2) {
        Calendar cDate1 = Calendar.getInstance();
        Calendar cDate2 = Calendar.getInstance();
        cDate1.setTime(date1);
        cDate1.set(Calendar.HOUR_OF_DAY, 0);
        cDate1.set(Calendar.MINUTE, 0);
        cDate1.set(Calendar.SECOND, 0);
        cDate1.set(Calendar.MILLISECOND, 0);

        cDate2.setTime(date2);
        cDate2.set(Calendar.HOUR_OF_DAY, 0);
        cDate2.set(Calendar.MINUTE, 0);
        cDate2.set(Calendar.SECOND, 0);
        cDate2.set(Calendar.MILLISECOND, 0);

        date1 = cDate1.getTime();
        date2 = cDate2.getTime();

        Date bigDay = null;
        Date smallDay = null;
        if (date1.after(date2)) {
            bigDay = date1;
            smallDay = date2;
        } else {
            bigDay = date2;
            smallDay = date1;
        }
        // return date1.getTime() / (24*60*60*1000) - date2.getTime() /
        // (24*60*60*1000);
        return (int) (bigDay.getTime() / 86400000 - smallDay.getTime() / 86400000);// 用立即数，减少乘法计算的开销
    }

    // 获取两个时间的差距的天数
    public static int diffDays2(Date date1, Date date2) {
        Calendar cDate1 = Calendar.getInstance();
        Calendar cDate2 = Calendar.getInstance();
        cDate1.setTime(date1);
        cDate1.set(Calendar.HOUR_OF_DAY, 0);
        cDate1.set(Calendar.MINUTE, 0);
        cDate1.set(Calendar.SECOND, 0);
        cDate1.set(Calendar.MILLISECOND, 0);

        cDate2.setTime(date2);
        cDate2.set(Calendar.HOUR_OF_DAY, 0);
        cDate2.set(Calendar.MINUTE, 0);
        cDate2.set(Calendar.SECOND, 0);
        cDate2.set(Calendar.MILLISECOND, 0);

        date1 = cDate1.getTime();
        date2 = cDate2.getTime();

        // return date1.getTime() / (24*60*60*1000) - date2.getTime() /
        // (24*60*60*1000);
        return (int) (date1.getTime() / 86400000 - date2.getTime() / 86400000);// 用立即数，减少乘法计算的开销
    }

    public static Date now() {
        return Date.from(LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant());
    }

    public static Date nowFormatYMD() {
        return getDateYMD(now());
    }

    public static Date getDateYMD(Date date) {
        if (date == null) {
            return null;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    public static Date max(Date dt1, Date dt2) {
        return dt1.compareTo(dt2) >= 0 ? dt1 : dt2;
    }

    public static Date min(Date dt1, Date dt2) {
        return dt1.compareTo(dt2) >= 0 ? dt2 : dt1;
    }

    // 把字符串转为日期
    public static Date parse(String _str, String _format) throws ParseException {
        Date dt = null;
        if (_str != null && _format != null) {
            SimpleDateFormat sdf = new SimpleDateFormat();
            sdf.setLenient(false);

            sdf.applyPattern(_format);

            ParsePosition pos = new ParsePosition(0);
            dt = sdf.parse(_str, pos);
            if (dt == null) {
                throw new ParseException("", pos.getErrorIndex());
            } else if (pos.getIndex() != _str.length()) {
                throw new ParseException("", pos.getIndex());
            }
        }
        return dt;
    }

    public static Date tryParse(String _str, String _format) {
        try {
            return parse(_str, _format);
        } catch (ParseException pe) {
            return null;
        }
    }

    // 把日期转为字符串
    public static String format(Date _date, String _format) {

        if (_date == null) {

            return null;
        }

        SimpleDateFormat sdf = new SimpleDateFormat();
        sdf.setLenient(false);
        sdf.applyPattern(_format);

        try {
            return sdf.format(_date);
        } catch (Exception ex) {
            return null;
        }
    }

    // 加几天
    public static Date addDays(Date date, int days) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.DATE, days);
        return calendar.getTime();
    }

    // 加几个月
    public static Date addMonths(Date date, int months) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, months);
        return calendar.getTime();
    }

    public static Date addMilliSecond(Date date, long timestamps) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTimeInMillis(date.getTime() + timestamps);
        return calendar.getTime();
    }

    // date1-date2返回相差年月 （精准到日）
    public static String diffYearMonthDay(Date oldDate, Date newDate) throws Exception {
        Calendar cal = Calendar.getInstance();
        if (oldDate == null) {
            return null;
        }
        if (newDate == null) {
            return null;
        }
        cal.setTime(newDate);
        if (cal.before(oldDate)) {
            throw new IllegalArgumentException(
                    "The birthDay is before Now.It's unbelievable!");
        }
        int yearNow = cal.get(Calendar.YEAR);
        int monthNow = cal.get(Calendar.MONTH);
        int dayOfMonthNow = cal.get(Calendar.DAY_OF_MONTH);
        cal.setTime(oldDate);

        int yearBirth = cal.get(Calendar.YEAR);
        int monthBirth = cal.get(Calendar.MONTH);
        int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);

        int age = yearNow - yearBirth;

        if (monthNow <= monthBirth) {
            if (monthNow == monthBirth) {
                if (dayOfMonthNow < dayOfMonthBirth) {
                    age--;
                }
            } else {
                age--;
            }
        }
        return String.valueOf(age);
    }

    /**
     * date2-date1返回相差月份
     *
     * @param date1 格式YYYYMM
     * @param date2 格式YYYYMM
     * @return
     * @throws Exception
     */
    public static int diffMonth(String date1, String date2, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        Calendar bef = Calendar.getInstance();
        Calendar aft = Calendar.getInstance();
        try {
            bef.setTime(sdf.parse(date1));
            aft.setTime(sdf.parse(date2));
        } catch (ParseException e) {
            e.printStackTrace();
        }
        int result = aft.get(Calendar.MONTH) - bef.get(Calendar.MONTH);
        int month = (aft.get(Calendar.YEAR) - bef.get(Calendar.YEAR)) * 12;
        return Math.abs(month + result);
    }

    public static int compare(Date d1, Date d2) {
        if (d1 == null && d2 == null) {
            return 0;
        } else if (d1 == null) {
            return 1;
        } else if (d2 == null) {
            return -1;
        } else {
            return d1.compareTo(d2);
        }
    }

    @SuppressWarnings("unused")
    public static int weekDayVaue(List<Integer> weekDay) {
        if (CollectionUtils.isEmpty(weekDay)) {
            return 0;
        }

        return weekDay.stream()
                .distinct()
                .sorted(Integer::compare)
                .limit(7)
                .reduce(0, (sum, p) -> sum += 1 << p);
    }

    @SuppressWarnings("unused")
    public static List<Integer> valueWeekDay(Integer weekValue) {
        List<Integer> list = new ArrayList<>();
        if (weekValue == null) {
            return list;
        }

        for (int i = 1; i <= 7; i++) {
            if (((1 << i) & weekValue) > 0) {
                list.add(i);
            }
        }
        return list;
    }

    // 获取指定日期所在月份第一天（0:00）
    public static Date firstDayOfThisMonth(Date input) {
        if (input == null) {
            return null;
        }
        LocalDate firstDay = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
                .with(TemporalAdjusters.firstDayOfMonth());
        return Date.from(firstDay.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
    }

    // 获取指定日期所在月份最后一天（23:59）
    public static Date lastDayOfMonth(Date input) {
        if (input == null) {
            return null;
        }
        LocalDate lastDay = input.toInstant().atZone(ZoneId.systemDefault()).toLocalDate()
                .with(TemporalAdjusters.lastDayOfMonth());
        return Date.from(lastDay.atTime(23, 59, 59, 999999999).atZone(ZoneId.systemDefault()).toInstant());
    }

    public static List<Date> display(Date dateFirst, Date dateSecond) {
        List<Date> list = new ArrayList<Date>();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        try {
            Date dateOne = dateFormat.parse(dateFormat.format(dateFirst));
            Date dateTwo = dateFormat.parse(dateFormat.format(dateSecond));
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(dateOne);
            while (calendar.getTime().getTime() <= dateTwo.getTime()) {
//				System.out.println(dateFormat.format(calendar.getTime()));
                list.add(calendar.getTime());
                calendar.add(Calendar.DAY_OF_MONTH, 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return list;
    }

    /**
     * 获取一个自然月的天数
     *
     * @param date
     * @return
     */
    public static int getDaysOfMonth(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    /**
     * 判读连个日期是否在一个月
     *
     * @param date1
     * @param date2
     * @return
     */
    public static boolean equalsMonth(Date date1, Date date2) {
        Calendar calendar1 = Calendar.getInstance();
        calendar1.setTime(date1);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(date2);
        int year1 = calendar1.get(Calendar.YEAR);
        int year2 = calendar2.get(Calendar.YEAR);
        int month1 = calendar1.get(Calendar.MONTH);
        int month2 = calendar2.get(Calendar.MONTH);
        return calendar1.get(Calendar.YEAR) == calendar2.get(Calendar.YEAR) && calendar1.get(Calendar.MONTH) == calendar2.get(Calendar.MONTH);
    }

    /**
     * 一段时间范围内的工作日
     *
     * @param startDate
     * @param endDate
     * @return
     */
    public static int getDutyDays(Date startDate, Date endDate) {
        int result = 0;
        if (startDate == null || endDate == null) {
            return result;
        }
        Calendar start = Calendar.getInstance();
        start.setTime(startDate);
        Calendar end = Calendar.getInstance();
        end.setTime(endDate);
        while (start.compareTo(end) <= 0) {
            if (start.get(Calendar.DAY_OF_WEEK) != 7 && start.get(Calendar.DAY_OF_WEEK) != 1) {
                result++;
            }
            start.add(Calendar.DAY_OF_MONTH, 1);
        }
        return result;
    }

    public static Map<String, Object> resolveDate(Date date, String prefix) {
        Map<String, Object> map = new HashMap<>();
        if (date == null) {
            return map;
        }
        SimpleDateFormat sdf = new SimpleDateFormat();
        sdf.setLenient(false);
        sdf.applyPattern(DATE_FORMAT_YYYY_MM_DD);
        try {
            String formatDate = sdf.format(date);
            String[] split = formatDate.split("-");
            if (split.length == 3) {
                map.put(prefix + "Year", split[0]);
                map.put(prefix + "Month", split[1]);
                map.put(prefix + "Day", split[2]);
            }
        } catch (Exception ex) {
            return map;
        }
        return map;
    }
}